home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / gnu / gnulib / libsrc98.zoo / crt0.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-01  |  14.0 KB  |  480 lines

  1. /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  2.  * NB: This file is used for both 16 and 32 bit code.
  3.  * USE NO "int"s IN HERE!!!!
  4.  *!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  5.  *
  6.  *
  7.  * Crt0: C run-time initialization code.
  8.  * Written by Eric R. Smith, and placed in the public domain.
  9.  * Use at your own risk.
  10.  *
  11.  * _start(base): sets things up for the process whose basepage is
  12.  *    base. In particular, it sets up a valid environment, shrinks the
  13.  *    TPA to a reasonable value, and parses the command line.
  14.  *
  15.  * 01/03/89 ++jrb
  16.  *    The (new) meaning of _stksize: (thanks to allan pratt for the feedback)
  17.  *
  18.  * 11/27/91 ++jrb
  19.  *     More meanings for _stksize (thanks to eric and allan for the feedback)
  20.  *
  21.  *    _stksize            meaning
  22.  *      -4L        keep 3/4, free 1/4, malloc from own heap
  23.  *      -3L        keep 2/4 (1/2), free 1/2 malloc from own heap
  24.  *      -2L        keep 1/4 of memory, free 3/4, malloc from own heap
  25.  *
  26.  *    NOTE: all of the following will do malloc from Malloc() first.
  27.  *    when that fails, in the -1L case malloc() will then do further
  28.  *    mallocs from our own heap. This lets us use the maximum amount of
  29.  *      memory in traditional ST's as well as in newer split address
  30.  *    STs. In the >=0 cases futher malloc()'s will fail, and they
  31.  *    will not try to malloc() from own heap. Out own space in the >= 0
  32.  *    cases are intended mainly for stack+alloca()'s.
  33.  *
  34.  *      -1L        keep all of memory (except MINFREE at top) and do
  35.  *            mallocs from own heap, with heap grown upwards towards
  36.  *            stack, and the stack growing down towards heap,
  37.  *            with a minimum slush between them so that they
  38.  *            dont meet (only checked while malloc'ing). With
  39.  *            this model, further spawning is not possible, but it is
  40.  *            well suited for programs such as gcc-cc1 etc.
  41.  *            Thanks to Piet van Oostrum & Atze Dijkstra for this idea
  42.  *
  43.  *    0L        keep minimum amount of memory. this is also the
  44.  *            case when _stksize is undefined by the user.
  45.  *    1L        keep 1/4 of memory, free 3/4 ( as in Alcyon GEMSTART)
  46.  *    2L        keep 2/4 (1/2), free rest
  47.  *    3L        keep 3/4, free 1/4
  48.  *    other        keep that many bytes
  49.  *    -other        keep |other| bytes and malloc from own heap
  50.  *
  51.  * 02/14/90 ++jrb (thanks edgar)
  52.  *    auto acc detect
  53.  *    undump friendly
  54.  *   Note: some of the stuff here may seem extraneous: these are in
  55.  *     prep for upcoming plug'n play device interface
  56.  *     (the moment the ol'boss lets me do some "real" work).
  57.  *
  58.  *
  59.  * NOTE: dumping applications should use _initial_stack instead: if
  60.  *     !=0, then _stksize is initialized from _initial_stack, and
  61.  *     mallocs are always from internal heap. (TeX works much better now),
  62.  *     thanks edgar!
  63.  *
  64.  * Acc convention:
  65.  *    user sets _heapbase to bottom of stack + heap area
  66.  *         sets _stksize to the size of this area
  67.  *         at startup, sp will be set to top of this area
  68.  *         (_heapbase  + _stksize ) and malloc()'s will happen from heap.
  69.  *        (note malloc() and *not* Malloc())
  70.  *     OR
  71.  *    user sets only _stksize. then _heapbase is set to Malloc(_stksize)
  72.  *    sp to _heapbase + _stksize and mallocs all happen from this heap.
  73.  *
  74.  * 02/16/90 ++jrb
  75.  *  - bug fix: dont get screwed by desktop launch when fast bit is set
  76.  *             convert env string to format usable
  77.  *        (atari get your act together!!)
  78.  */
  79.  
  80. #include <basepage.h>
  81. #include <osbind.h>
  82. #ifndef _COMPILER_H
  83. #include <compiler.h>
  84. #endif
  85. #include <stddef.h>
  86.  
  87. #define isspace(c) ((c) == ' '||(c) == '\t')
  88. #define BUFSIZ    ((unsigned long)1024)    /* this must track the value */
  89.                     /* in stdio.h                */
  90. #define MINFREE    (8L * 1024L)        /* free atleast this much mem */
  91.                     /* on top */
  92. #define MINKEEP (8L * 1024L)        /* keep atleast this much mem */
  93.  
  94. /*
  95.  * this little goodie is for emacs
  96.  * edgar: note: it has grown two leading '_',
  97.  *              adjust in emacs/src/sysdep.c:start_of_data()
  98.  *
  99.  * __data_start removed, as that can be determined from the basepage.
  100.  */
  101.  
  102. BASEPAGE *_base;
  103. char **environ;
  104. static long argc;
  105. static char **argv;
  106.  
  107. /*
  108.  * initial stack is used primarily by dumping application,
  109.  * if it is, malloc is always from heap, and _stksize is init
  110.  * from initial_stack (to preserve the value in the undumped run)
  111.  */
  112. long _initial_stack;            /* .comm __initial_size, 4 */
  113. extern long _stksize;            /* picked up from user or stksiz.c */
  114. /* set to heap base addr when (_stksize <= -1L) || _initial_stack || When DA */
  115. void *_heapbase;
  116.  
  117. /* default sizeof stdio buffers */
  118. size_t __DEFAULT_BUFSIZ__;    /* .comm             */
  119.  
  120. /* are we an app? */
  121. short _app;
  122.  
  123. /* are we on a split addr mem ST */
  124. short _split_mem = 0;
  125.  
  126. /* externs to pull in ident strings of all used libraries into the
  127.    executable. if a library is not used, then the extern is satisfied
  128.    by a dummy in the library
  129.  */
  130. asm("
  131.     .globl ___Ident_libg
  132.     .globl ___Ident_curses
  133.     .globl ___Ident_widget
  134.     .globl ___Ident_gem
  135.     .globl ___Ident_pml
  136.     .globl ___Ident_gnulib
  137.      ");
  138.  
  139. static void _acc_main __PROTO((void));
  140. static void _start1 __PROTO((BASEPAGE *bp));
  141. static long parseargs __PROTO((BASEPAGE *bp));
  142. static void setup_handlers __PROTO((void));
  143. static void _start0 __PROTO((BASEPAGE *));
  144. static void setup_handlers __PROTO((void));
  145. __EXTERN void _main __PROTO((long, char **, char **));
  146. __EXTERN void _init_signal __PROTO((void));
  147. __EXTERN void _start __PROTO((BASEPAGE *));
  148. #ifdef __GCRT0__
  149. __EXTERN void monstartup __PROTO((void *lowpc, void *highpc));
  150. __EXTERN void monitor __PROTO((void *lowpc, void *highpc, void *buffer, unsigned long bufsize, unsigned int nfunc));
  151. __EXTERN void moncontrol __PROTO((long flag));
  152. __EXTERN void _mcleanup __PROTO((void));
  153. __EXTERN int profil __PROTO((void *buff, unsigned long bufsiz, unsigned long offset, int shift));
  154. #endif
  155.  
  156. /*
  157.  * From: kbad@atari.UUCP (Ken Badertscher)
  158.  * Newsgroups: comp.sys.atari.st
  159.  * Subject: Am I a DA? (long)
  160.  *   .....
  161.  * I mentioned before that a DA's registers are garbage on startup, well,
  162.  * that's not entirely true.  When the DA gets control, register A0 always
  163.  * points to its basepage.  When a program is started by a GEMDOS Pexec(),
  164.  * register A0 is always cleared.  Using this fact, it is possible to
  165.  * implement startup code which gets the basepage address from register A0
  166.  * if the code is launched as a DA, or at 4(sp) if the code is launched by
  167.  * Pexec().  Since it knows how it was launched, it can also do the stack
  168.  * setup required of a DA, otherwise it can use the stack pointer it gets.
  169.  *
  170.  */
  171. /*
  172.  * revert back to testing A0 (instead of SP) after controversy on the net.
  173.  * packers will just have to fix themselves.
  174.  * in addition to testing A0 check long A0@(36) (parents basepage). for an
  175.  * acc this should be NULL.
  176.  */
  177. __asm__("
  178.      .text                
  179.      .even                
  180.      .globl __start            
  181. __start:
  182. "
  183. #ifdef __MBASE__
  184. "    movl    a0,a1            /* Find basepage, data seg */
  185.     cmpw    #0,a1
  186.     jne    1f
  187.     movl    sp@(4),a1
  188. 1:
  189.     movl    a1@(16)," __MBASESTR__ "    /* Set base to data seg + 32K */
  190.     subw    #32768," __MBASESTR__ "
  191.  
  192. "
  193. #define    Base    __MBASESTR__ "@(__base)"
  194. #define Heapbase __MBASESTR__ "@(__heapbase)"
  195. #define Stksize    __MBASESTR__ "@(__stksize)"
  196. #else
  197. #define Base    "__base"
  198. #define Heapbase "__heapbase"
  199. #define Stksize "__stksize"
  200. #endif
  201. "    cmpw    #0,a0             /* test acc or prog  */
  202.      jeq    __start0         /* br if prog          */
  203.     tstl    a0@(36)             /* tst parent basepage pointer */
  204.     jne     __start0         /* its a prog if != 0  */
  205.  
  206.  /* its an acc, set up a stck+heap */
  207.     movl    a0," Base "         /* sto basepage    */
  208.     tstl    " Heapbase "         /* setup _heapbase and sp */
  209.     jne    1f
  210.     movl    " Stksize ",d3         /* _heapbase not specified */
  211.     addql    #3, d3
  212.     andl    #0xfffffffc,d3
  213.     movl    d3,sp@-             /* _heapbase = Malloc(_stksize) */
  214.         movw    #0x48,sp@-
  215.     trap    #1
  216.     addqw    #6,sp
  217.     movl    d0," Heapbase "
  218.     addl    d3,d0
  219.     movl    d0, sp              /* sp = _heapbase + _stksize */
  220.     jra    __acc_main
  221. 1:                     /* heap base specified */
  222.      movl    " Heapbase ",sp         /* setup sp        */
  223.      addl    " Stksize ",sp        
  224.      jra    __acc_main
  225.     .data");               /* acc main          */
  226.                        /* dont even think of */
  227.                        /* dropping through    */
  228.  
  229. static char    *acc_argv[] = {"", (char *) 0}; /* no name and no arguments */
  230.  
  231. static void _acc_main(void)
  232. {
  233.     _app = 0;                /* this is an accessory */
  234.     _main(1L, acc_argv, acc_argv);
  235.     /*NOTREACHED*/
  236. }
  237.  
  238. void _start0(bp) /* bp is passed at sp@(4) */
  239.     register BASEPAGE *bp;
  240. {
  241.     /* temporarily set sp at hitpa (rounded),then call the real
  242.        startup function. not doing this was blowing up the
  243.        stack provided by gemdos on a 1040, because _start1()
  244.        was pushing too many reggies on the stack
  245.        _start1() will finally set sp to its final value and
  246.        then do a mshrink().
  247.     */
  248.     asm volatile("movl %0,sp" ::"r"((long)bp->p_hitpa & ~3L));
  249.     _start1(bp);
  250. }
  251.  
  252. static void _start1(bp)
  253.     register BASEPAGE *bp __asm("a3");
  254. {
  255.     register long m __asm("d3");
  256.     register long freemem __asm("d4");
  257.     extern void etext();        /* fake-out if pcrel used */
  258.     
  259.     _app = 1;    /* its an application */
  260.     _base = bp;
  261.     if(!__DEFAULT_BUFSIZ__)
  262.         __DEFAULT_BUFSIZ__ = BUFSIZ;
  263.  
  264.     m = parseargs(bp);    /* m = # bytes used by environment + args */
  265. /* make m the total number of bytes required by program sans stack/heap */
  266.     m += (bp->p_tlen + bp->p_dlen + bp->p_blen + sizeof(BASEPAGE));
  267.     m = (m + 3L) & (~3L);
  268. /* freemem the amount of free mem accounting for MINFREE at top */
  269.     if((freemem = (long)bp->p_hitpa - (long)bp - MINFREE - m) <= 0L)
  270.         goto notenough;
  271.     
  272.     if(_initial_stack)
  273.     {
  274.         /* the primary use of _initial_stack will be in dumping */
  275.         /* applications where only a heap for malloc makes sense */
  276.         _heapbase = (void *) ((long)bp + m);
  277.         _stksize = _initial_stack;
  278.     }
  279.     
  280.     if((_stksize <  -1L))
  281.     {
  282.         _heapbase = (void *) ((long)bp + m);
  283.         _stksize = -_stksize - 1;
  284.         }
  285.         
  286.     if((!_initial_stack) && (_stksize >= -1L))
  287.         {   /* malloc from Malloc first, then from own heap */
  288.         _split_mem = 1;
  289.         }
  290.  
  291.     switch(_stksize)
  292.     {
  293.       case -1L:    /* keep all but MINFREE */
  294.         _stksize = freemem;
  295.         _heapbase = (void *) ((long)bp + m);
  296.         break;
  297.         
  298.       case 0L:    /* free all but MINKEEP */
  299.         _stksize = MINKEEP;
  300.         break;
  301.  
  302.       case 1L:    /* keep 1/4, free 3/4 */
  303.         _stksize = freemem >> 2;
  304.         break;
  305.  
  306.       case 2L:    /* keep 1/2, free 1/2 */
  307.         _stksize = freemem >> 1;
  308.         break;
  309.  
  310.       case 3L:    /* keep 3/4, free 1/4 */
  311.         _stksize = freemem - (freemem >> 2); 
  312.         break;
  313.  
  314.       default:
  315.         /* if _stksize > 0, keep that much */
  316.         break;
  317.     }
  318.     
  319. /* make m the total number of bytes including stack */
  320.     _stksize = _stksize & (~3L);
  321.     m += _stksize;
  322.  
  323. /* make sure there's enough room for the stack */
  324.     if (((long)bp + m) > ((long)bp->p_hitpa - MINFREE))
  325.         goto notenough;
  326.  
  327. /* set up the new stack to bp + m  */
  328.     asm volatile("\
  329.          movl    %0, sp  | move base to sp
  330.          addal    %1, sp    | add total bytes"
  331.              :            /* outputs */
  332.              : "g"(bp), "g"(m)    /* inputs  */
  333.              );     /* we dont tell gcc about clobbered reggies */
  334.     
  335. /* shrink the TPA - this is always correct, shared text or not -- hyc */
  336.     (void)Mshrink(bp, m);
  337.     asm volatile("subl a6,a6");    /* clear link reg for gdb */
  338.     
  339. /* establish handlers,  call the main routine */
  340.     setup_handlers();
  341. #ifdef __GCRT0__
  342.     monstartup((void *)(bp->p_tbase), (void *)etext-1);
  343. #endif
  344.     _main(argc, argv, environ);
  345.     /* not reached normally */
  346.  
  347. notenough:
  348.     Cconws("Fatal error: insufficient memory\r\n");
  349.         Pterm(-1);
  350. }
  351.  
  352.  
  353. /*
  354.  * parseargs(bp): parse the environment and arguments pointed to by the
  355.  * basepage. Return the number of bytes of environment and arguments
  356.  * that have been appended to the bss area (the environ and argv arrays
  357.  * are put here, as is a temporary buffer for the command line, if
  358.  * necessary).
  359.  *
  360.  * The MWC extended argument passing scheme is assumed.
  361.  *
  362.  */
  363.  
  364. static long parseargs(bp)
  365.     BASEPAGE *bp;
  366. {
  367.         long count = 4;        /* compensate for aligning */
  368.     long  i;
  369.     char *from, *cmdln, *to;
  370.     char **envp, **arg;
  371.     
  372. /* handle the environment first */
  373.  
  374.     environ = envp = (char **)(( (long)bp->p_bbase + bp->p_blen + 4) & (~3));
  375.     from = bp->p_env;
  376.     while (*from) {
  377.  
  378. /* if we find MWC arguments, tie off environment here */
  379.         if (*from == 'A' && *(from+1) == 'R' && *(from+2) == 'G' &&
  380.             *(from+3) == 'V' && *(from+4) == '=') {
  381.             *envp++ = (char *) 0; count += 4;
  382.             *from++ = 0;
  383. #ifdef STRICTLY_COMPATIBLE_WITH_STANDARD
  384.             if (bp->p_cmdlin[0] != 127)
  385.                 goto old_cmdlin;
  386. #endif
  387.             while (*from++) ; /* skip ARGV= string */
  388.             argv = arg = envp++;
  389.             *arg++ = from; count+= 4;
  390.             while (*from++) ; /* skip argv[0] */
  391.             goto do_argc;
  392.         }
  393.         *envp++ = from;
  394.         count += 4;
  395.         while (*from++);
  396.  
  397.         /* if launched from desktop -- fix up env
  398.                  * be careful while doing this, as the environment
  399.          * may have a variable whose value is the empty
  400.          * string. (make puts a MAKFLAGS=\0). The desktop
  401.          * typically has "PATH=\0C:\\0\0", so to distinguish
  402.          * the two cases, check for uppercase drive letter
  403.          * followed by ":\\"
  404.          */
  405. #define ISDRV(x) (('A' <= (x)) && ((x) <= 'Z'))
  406.          if ( (from[ -2 ] == '=') && (ISDRV(*from)) && 
  407.              (from[1] == ':') && (from[2] == '\\') )
  408.         {
  409.             char *p = &from[-1]; /* typically  "PATH=\0C:\\0\0" */
  410.             while(*from)
  411.             *p++ = *from++;
  412.             *p = '\0'; from++;
  413.         }
  414.     }
  415.     *envp++ = (char *)0;
  416.     count += 4;
  417.  
  418. /* Allocate some room for the command line to be parsed */
  419.     cmdln = bp->p_cmdlin;
  420.     i = *cmdln++;
  421.     from = to = (char *) envp;
  422.     if (i > 0) {
  423.         count += (i&(~3));
  424.         envp = (char **) ( ((long) envp)  + (i&(~3)) );
  425.     }
  426.     envp += 2; count += 8;
  427.  
  428. /* Now parse the command line and put argv after the environment */
  429.  
  430.     argv = arg = envp;
  431.     *arg++ = "";        /* argv[0] not available */
  432.     count += 4;
  433.     while(i > 0 && isspace(*cmdln) )
  434.         cmdln++,--i;
  435.  
  436.     while (i > 0) {
  437.         if (isspace(*cmdln)) {
  438.             --i; cmdln++;
  439.             while (i > 0 && isspace(*cmdln))
  440.                 --i,cmdln++;
  441.             *to++ = 0;
  442.         }
  443.         else {
  444.             if (!(*to++ = *cmdln++)) break;
  445.             --i;
  446.         }
  447.     }
  448.     *to++ = '\0';
  449.     *to = '\0'; /* bug fix example:cmdln == '\3' 'a' ' ' 'b' '\0' */
  450.     /* the loop below expects \0\0 at end to terminate! */
  451.     /* the byte @ cmdln[i+2] != 0 when fast bit is set */
  452. do_argc:
  453.     argc = 1;        /* at this point argv[0] is done */
  454.     while (*from) {
  455.         *arg++ = from;
  456.         argc++;
  457.         count += 4;
  458.         while(*from++) ;
  459.     }
  460.     *arg++ = (char *) 0;
  461.     return count+4;
  462. }
  463.  
  464. static void setup_handlers(void)
  465. {
  466.     /* more stuff to come */
  467.     _init_signal();
  468. }
  469.  
  470. void __exit(status)
  471.     long status;
  472. {
  473. #ifdef __GCRT0__
  474.     moncontrol(0L);
  475.     _mcleanup();
  476. #endif
  477.     Pterm(status);
  478.  
  479. }
  480.